; ModuleID = 'hw1.ll'
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
target triple = "i386-pc-linux-gnu"

%struct.MPI_Status = type { i32, i32, i32, i32, i32 }
%struct.ompi_communicator_t = type opaque
%struct.ompi_datatype_t = type opaque
%struct.ompi_predefined_communicator_t = type opaque
%struct.ompi_predefined_datatype_t = type opaque
%struct.ompi_request_t = type opaque

@myid = common global i32 0
@ompi_mpi_comm_world = external global %struct.ompi_predefined_communicator_t
@ompi_mpi_int = external global %struct.ompi_predefined_datatype_t
@nprocs = common global i32 0
@.str = private constant [16 x i8] c"Node %d has %d\0A\00", align 1
@.str1 = private constant [17 x i8] c"Global sum = %d\0A\00", align 1

define i32 @global_sum(i32 %partial) nounwind {
entry:
  %recv_status2 = alloca %struct.MPI_Status
  %recv_request2 = alloca %struct.ompi_request_t*
  %send_status1 = alloca %struct.MPI_Status
  %send_request1 = alloca %struct.ompi_request_t*
  %partial_addr = alloca i32
  %retval = alloca i32
  %0 = alloca i32
  %status = alloca %struct.MPI_Status
  %mydone = alloca i32
  %hisdone = alloca i32
  %partner = alloca i32
  %l = alloca i32
  %"alloca point" = bitcast i32 0 to i32
  store i32 %partial, i32* %partial_addr
  %1 = load i32* %partial_addr, align 4
  store i32 %1, i32* %mydone, align 4
  store i32 0, i32* %l, align 4
  br label %bb3

bb:                                               ; preds = %bb3
  %2 = load i32* %l, align 4
  %3 = sitofp i32 %2 to double
  %4 = call double @llvm.pow.f64(double 2.000000e+00, double %3)
  %5 = fptosi double %4 to i32
  %6 = load i32* @myid, align 4
  %7 = xor i32 %5, %6
  store i32 %7, i32* %partner, align 4
  %mydone1 = bitcast i32* %mydone to i8*
  %8 = load i32* %partner, align 4
  %9 = call i32 @MPI_Isend(i8* %mydone1, i32 1, %struct.ompi_datatype_t* bitcast (%struct.ompi_predefined_datatype_t* @ompi_mpi_int to %struct.ompi_datatype_t*), i32 %8, i32 10, %struct.ompi_communicator_t* bitcast (%struct.ompi_predefined_communicator_t* @ompi_mpi_comm_world to %struct.ompi_communicator_t*), %struct.ompi_request_t** %send_request1) nounwind
  %10 = call i32 @MPI_Wait(%struct.ompi_request_t** %send_request1, %struct.MPI_Status* %send_status1) nounwind
  %hisdone2 = bitcast i32* %hisdone to i8*
  %11 = load i32* %partner, align 4
  %12 = call i32 @MPI_Irecv(i8* %hisdone2, i32 1, %struct.ompi_datatype_t* bitcast (%struct.ompi_predefined_datatype_t* @ompi_mpi_int to %struct.ompi_datatype_t*), i32 %11, i32 10, %struct.ompi_communicator_t* bitcast (%struct.ompi_predefined_communicator_t* @ompi_mpi_comm_world to %struct.ompi_communicator_t*), %struct.ompi_request_t** %recv_request2) nounwind
  %13 = call i32 @MPI_Wait(%struct.ompi_request_t** %recv_request2, %struct.MPI_Status* %recv_status2) nounwind
  %14 = load i32* %mydone, align 4
  %15 = load i32* %hisdone, align 4
  %16 = add nsw i32 %14, %15
  store i32 %16, i32* %mydone, align 4
  %17 = load i32* %l, align 4
  %18 = add nsw i32 %17, 1
  store i32 %18, i32* %l, align 4
  br label %bb3

bb3:                                              ; preds = %bb, %entry
  %19 = load i32* @nprocs, align 4
  %20 = sitofp i32 %19 to double
  %21 = call double @llvm.log2.f64(double %20)
  %22 = fptosi double %21 to i32
  %23 = load i32* %l, align 4
  %24 = icmp sgt i32 %22, %23
  br i1 %24, label %bb, label %bb4

bb4:                                              ; preds = %bb3
  %25 = load i32* %mydone, align 4
  store i32 %25, i32* %0, align 4
  %26 = load i32* %0, align 4
  store i32 %26, i32* %retval, align 4
  br label %return

return:                                           ; preds = %bb4
  %retval5 = load i32* %retval
  ret i32 %retval5
}

declare double @llvm.pow.f64(double, double) nounwind readonly

declare i32 @MPI_Send(i8*, i32, %struct.ompi_datatype_t*, i32, i32, %struct.ompi_communicator_t*)

declare i32 @MPI_Recv(i8*, i32, %struct.ompi_datatype_t*, i32, i32, %struct.ompi_communicator_t*, %struct.MPI_Status*)

declare double @llvm.log2.f64(double) nounwind readonly

define i32 @main(i32 %argc, i8** %argv) nounwind {
entry:
  %argc_addr = alloca i32
  %argv_addr = alloca i8**
  %retval = alloca i32
  %partial = alloca i32
  %sum = alloca i32
  %"alloca point" = bitcast i32 0 to i32
  store i32 %argc, i32* %argc_addr
  store i8** %argv, i8*** %argv_addr
  %0 = call i32 @MPI_Init(i32* %argc_addr, i8*** %argv_addr) nounwind
  %1 = call i32 @MPI_Comm_rank(%struct.ompi_communicator_t* bitcast (%struct.ompi_predefined_communicator_t* @ompi_mpi_comm_world to %struct.ompi_communicator_t*), i32* @myid) nounwind
  %2 = call i32 @MPI_Comm_size(%struct.ompi_communicator_t* bitcast (%struct.ompi_predefined_communicator_t* @ompi_mpi_comm_world to %struct.ompi_communicator_t*), i32* @nprocs) nounwind
  %3 = load i32* @myid, align 4
  %4 = add nsw i32 %3, 1
  store i32 %4, i32* %partial, align 4
  %5 = load i32* @myid, align 4
  %6 = load i32* %partial, align 4
  %7 = call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([16 x i8]* @.str, i32 0, i32 0), i32 %5, i32 %6) nounwind
  %8 = load i32* %partial, align 4
  %9 = call i32 @global_sum(i32 %8) nounwind
  store i32 %9, i32* %sum, align 4
  %10 = load i32* @myid, align 4
  %11 = icmp eq i32 %10, 0
  br i1 %11, label %bb, label %bb1

bb:                                               ; preds = %entry
  %12 = load i32* %sum, align 4
  %13 = call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([17 x i8]* @.str1, i32 0, i32 0), i32 %12) nounwind
  br label %bb1

bb1:                                              ; preds = %bb, %entry
  %14 = call i32 @MPI_Finalize() nounwind
  br label %return

return:                                           ; preds = %bb1
  %retval2 = load i32* %retval
  ret i32 %retval2
}

declare i32 @MPI_Init(i32*, i8***)

declare i32 @MPI_Comm_rank(%struct.ompi_communicator_t*, i32*)

declare i32 @MPI_Comm_size(%struct.ompi_communicator_t*, i32*)

declare i32 @printf(i8* noalias, ...) nounwind

declare i32 @MPI_Finalize()

declare i32 @MPI_Isend(i8*, i32, %struct.ompi_datatype_t*, i32, i32, %struct.ompi_communicator_t*, %struct.ompi_request_t**)

declare i32 @MPI_Irecv(i8*, i32, %struct.ompi_datatype_t*, i32, i32, %struct.ompi_communicator_t*, %struct.ompi_request_t**)

declare i32 @MPI_Wait(%struct.ompi_request_t**, %struct.MPI_Status*)
